package com.lry.app;

import com.lry.core.StateMachine;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.rocksdb.Checkpoint;
import org.rocksdb.Options;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;
import java.io.File;
import java.nio.charset.StandardCharsets;

@Slf4j
public class ExampleStateMachine implements StateMachine {

    static {
        RocksDB.loadLibrary();
    }

    private RocksDB db;
    private String raftDataDir;

    public ExampleStateMachine(String raftDataDir) {
        this.raftDataDir = raftDataDir;

         Options options = new Options();
        options.setCreateIfMissing(true);
        try {
            this.db = RocksDB.open(options, raftDataDir);
        } catch (RocksDBException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void writeSnapshot(String snapshotDir) {
        Checkpoint checkpoint = Checkpoint.create(db);
        try {
            checkpoint.createCheckpoint(snapshotDir);
        } catch (Exception ex) {
            ex.printStackTrace();
            log.warn("writeSnapshot meet exception, dir={}, msg={}",
                    snapshotDir, ex.getMessage());
        }
    }

    @Override
    public void readSnapshot(String snapshotDir) {
        try {
            // copy snapshot dir to data dir
            if (db != null) {
                db.close();
            }
            String dataDir = raftDataDir + File.separator + "rocksdb_data";
            File dataFile = new File(dataDir);
            if (dataFile.exists()) {
                FileUtils.deleteDirectory(dataFile);
            }
            File snapshotFile = new File(snapshotDir);
            if (snapshotFile.exists()) {
                FileUtils.copyDirectory(snapshotFile, dataFile);
            }
            // open rocksdb data dir
            Options options = new Options();
            options.setCreateIfMissing(true);
            db = RocksDB.open(options, dataDir);
        } catch (Exception ex) {
            log.warn("meet exception, msg={}", ex.getMessage());
        }
    }

    @Override
    public byte[] apply(byte[] data) {
        try {
            String command = new String(data);
            String[] commands = command.split(" ");
            //key value
            db.put(commands[1].getBytes(), commands[2].getBytes());
        } catch (Exception ex) {
            log.warn("meet exception, msg={}", ex.getMessage());
        }
        return "OK".getBytes();
    }


    @Override
    public byte[] get(byte[] keyBytes) {
        try {
            return db.get(keyBytes);
        } catch (RocksDBException ex) {
            log.warn("read rockdb error, msg={}", ex.getMessage());
            return null;
        }
    }

    @Override
    public void tobeMaster(boolean isMaster) {

    }


}
